#include <iostream>
#include <unistd.h>
#include <string>
#include <cstring>
#include <fcntl.h>

bool SetNonBlock(int fd)
{
    int fl = fcntl(fd, F_GETFL); // 获取文件描述符的状态。是一个位图
    if (fl < 0)
    {
        std::cerr << "fcntl error" << std::endl;
        return false;
    }
    fcntl(fd, F_SETFL, fl | O_NONBLOCK); // 设置文件描述符状态,第三个参数是设置完之后的状态
    return true;
}

int main()
{
    SetNonBlock(0);
    char buffer[1024];
    while (true)
    {
        std::cout << "please read: "; // 因为这里缺少\n刷新缓冲区，所以我们选择fflush手动刷新缓冲区，使这句话打印出来先。
                                      // 否则这句话会因为read的阻塞而一直留在缓冲区里面，等待我们输入之后才会被打印出来
                                      // 就会照成我们输入后，然后打印please read: ，再cout输入内容的奇怪现象
        fflush(0);
        errno = 0;
        ////////////////////////////////////////////////////////////////////////////////
        // 核心内容，read是阻塞IO
        ssize_t size = read(0, buffer, sizeof(buffer) - 1); // 从0号套接字中读取，即从键盘读取
        if (size < 0)                                       // 数据没就绪 或 中断
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK) // 底层没有数据就绪
            {
                std::cout << "[no data] errno: " << errno << " strerror: " << strerror(errno) << std::endl;
                sleep(1);
                continue;
            }
            else if (errno == EINTR) // 在读取数据之前被信号中断(中断)
            {
                std::cout << "[interrupt] errno: " << errno << " strerror: " << strerror(errno) << std::endl;
                // fflush(0);
                sleep(1);
                continue;
            }
            else
            {   //出错
                std::cerr << "read error" << std::endl;
                break;
            }
        }
        else // s>=0
        {
            std::cout << "[success] errno: " << errno << " strerror: " << strerror(errno) << std::endl;

            buffer[size - 1] = '\0'; // 因为buffer[size-1]='\n'，回车也会在buffer里面，所以我们为了打印时不多打印一行回车，就将其去掉
            // std::cout<<buffer<<std::endl;
            if (strcmp(buffer, "quit") == 0)
            {
                std::cout << "Bye" << std::endl;
                break;
            }
            std::cout << "echo# " << buffer << std::endl;
        }

        ////////////////////////////////////////////////////////////////////////////////
    }
    fd_set a;
    timeval t;
    
    return 0;
}